#pragma once

#include "bitmapData.h"
#include "IDataIoTemp.h"

#include "ImportExport.h"

namespace FTLib
{

	class CDataBase
	{
	protected:
		static const char BINARYMAGIC[12];
		static void ThrowIfFailed(const char* function, HRESULT hr);
		static void ThrowIfFailed(const char* function, HRESULT hr, std::function<bool(HRESULT)> checkFunc);
	};

	/*enum class LoadDataFormat
	{
	Invalid,
	WIC,
	CSV
	};*/

	//class loadsavedata_exception : std::exception
	//{
	//private:
	//	std::wstring msg;
	//public:
	//	loadsavedata_exception(const wchar_t* errorMsg) :msg(errorMsg){};

	//	const std::wstring& getErrorMessage() const { return this->msg; }
	//};

	class CDataLoad : protected CDataBase
	{
	private:
		std::wstring	fileName;
		LoadDataFormat	dataFormat;
	public:
		CDataLoad(const wchar_t* fileName, LoadDataFormat fmt = LoadDataFormat::Invalid);
		CDataLoad(const std::wstring& filename, LoadDataFormat fmt = LoadDataFormat::Invalid) : CDataLoad(filename.c_str(), fmt) {};

		std::shared_ptr<IBitmapData> ReadAsFloat32(std::uint32_t extraRows = 0, std::uint32_t extraColumns = 0);

	private:
		std::shared_ptr<IBitmapData> ReadWithWIC(const wchar_t* fileName, std::function<std::shared_ptr<IBitmapData>(PixelType pixelType, int width, int height)> func);

		std::shared_ptr<IBitmapData> ReadCSV(const wchar_t* fileName, std::function<std::shared_ptr<IBitmapData>(PixelType pixelType, int width, int height)> func);
		std::shared_ptr<IBitmapData> ReadBINARY(const wchar_t* fileName, std::function<std::shared_ptr<IBitmapData>(PixelType pixelType, int width, int height)> func);
		static LoadDataFormat DetermineLoadDataFormatFromExtension(const std::wstring& filename);

		struct CSVBitmapInfo
		{
			uint32_t width, height;
			PixelType pixelType;
		};

		CComPtr<IWICBitmapSource> Convert(IWICImagingFactory* pImgFactory, CComPtr<IWICBitmapFrameDecode> src);

		static bool ParseInfoLine(const std::string& infoLine, CSVBitmapInfo& bitmapInfo);
		static void GetDimensionByParsingCSVFile(std::ifstream& inputFile, CSVBitmapInfo& bitmapInfo);
		static int CountNumbersInLine(const std::string& line);
		static bool ParseLineFloat(const std::string& line, float* ptr, uint32_t width);

		static void ThrowErrorReadingCsv(const wchar_t* fileName);
		void CopyToFloatBitmap(IWICBitmapSource* spFormatConverted, std::shared_ptr<IBitmapData> dest);
	};

	//enum class SaveDataFormat
	//{
	//	Invalid,
	//	PNG,
	//	TIFF,
	//	WDP,	// JPG-XR
	//	CSV,
	//	FROM_EXTENSION
	//};

	class CSaveData : protected CDataBase
	{
	private:
		std::wstring	fileName;
		SaveDataFormat	format;
	public:
		CSaveData(const wchar_t* fileName, SaveDataFormat dataFormat);
		CSaveData(const std::wstring fileName, SaveDataFormat dataFormat) : CSaveData(fileName.c_str(), dataFormat){};

		void	SaveAsFloat32(std::shared_ptr<IBitmapData> bitmap);
		void	SaveAsGray16(std::shared_ptr<IBitmapData> bitmap);
		void	SaveAsGray8(std::shared_ptr<IBitmapData> bitmap);
	private:
		void SaveWithWIC(const wchar_t* filename, const GUID encoder, const WICPixelFormatGUID& wicPixelFmt, std::shared_ptr<IBitmapData> bitmap);
		void SaveWithWIC(IWICImagingFactory* pFactory, IWICStream* destStream, const GUID encoder, const WICPixelFormatGUID& wicPixelFmt, std::shared_ptr<IBitmapData> bitmap);

		void SaveAsCSV(const wchar_t* filename, std::shared_ptr<IBitmapData> bitmap);
		void SaveAsBINARY(const wchar_t* filename, std::shared_ptr<IBitmapData> bitmap);

		static void DeterminePixeltypeString(std::shared_ptr<IBitmapData> bitmap, std::string& str);
		static void DetermineFourierTransformDataLayoutString(std::shared_ptr<IBitmapData> bitmap, std::string& str);
	};

	std::shared_ptr<IBitmapData> CreateRandomFloat32Image(uint32_t width, uint32_t height, FTLib::PixelType pixelType, float low, float high, uint32_t seed);

}